//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "ddk.h"
#include <stub.h>
#include "CBasicFileSystem.h"
#include "FileSystemControl.h"

extern IDeviceDriver * CDECL CreateBlkFlash(uint_t uDeviceNo, void *pvParameter);

class ktfsdev : public CDeviceDriver
{
public:
    CARAPI Read(
                    /* [in] */ Int64 u64Offset,
                    /* [in] */ Int32 bytesToRead,
                    /* [out] */ MemoryBuf * pBuffer,
                    /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
                    /* [in] */ Int64 u64Offset,
                    /* [in] */ const MemoryBuf & buffer,
                    /* [out] */ Int32 * pBytesWritten,
                    /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
                    /* [in] */ Handle32 nControlCode,
                    /* [in] */ const MemoryBuf & inBuffer,
                    /* [out] */ MemoryBuf * pOutBuffer,
                    /* [out] */ IEvent * * ppCompletionEvent);
    virtual ~ktfsdev();
    virtual void Dispose();
};

CARAPI ktfsdev::Read(
                /* [in] */ Int64 u64Offset,
                /* [in] */ Int32 bytesToRead,
                /* [out] */ MemoryBuf * pBuffer,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    return NOERROR;
}

CARAPI ktfsdev::Write(
                /* [in] */ Int64 u64Offset,
                /* [in] */ const MemoryBuf & buffer,
                /* [out] */ Int32 * pBytesWritten,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    return NOERROR;
}

CARAPI ktfsdev::Control(
                /* [in] */ Handle32 nControlCode,
                /* [in] */ const MemoryBuf & inBuffer,
                /* [out] */ MemoryBuf * pOutBuffer,
                /* [out] */ IEvent * * ppCompletionEvent)
{
    wchar_t *serviceName = NULL;
    IBasicFileSystem *pIBFS = NULL;
    ECode ec;
    IStub *pStub = NULL;

    if (inBuffer.IsNullOrEmpty()) {
        return E_INVALID_ARGUMENT;
    }
    serviceName = (wchar_t *)inBuffer.GetPayload();
    assert(wcslen(serviceName) > 0);

    switch (nControlCode) {
        case FILESYSTEM_CONTROL_CREATE:
            pIBFS = new CKtfsFileSystem();
            if (NULL == pIBFS) {
                kprintf("Create File System failed\n");
                return E_OUT_OF_MEMORY;
            }
            pIBFS->AddRef();

            ec = DzRegisterService(serviceName, pIBFS, &pStub);
            if (ec != NOERROR) {
                kprintf("Register service failed\n");
                pIBFS->Release();
                return ec;
            }
            assert(pStub != NULL);
            ((CKtfsFileSystem*)pIBFS)->SetStub(pStub);
            pIBFS->Release();

            break;

        case FILESYSTEM_CONTROL_DELETE:
            ec = DzFindService(serviceName, (PInterface *)&pIBFS);
            if (ec != NOERROR) {
                kprintf("Find service failed.\n");
                return ec;
            }

            pStub = ((CKtfsFileSystem*)pIBFS)->GetStub();
            assert(pStub != NULL);

            ec = DzUnregisterService(serviceName, pStub);
            if (ec != NOERROR) {
                kprintf("Unregisterservice failed.\n");
                return ec;
            }
            pIBFS->Release();
            break;

        default:
            break;
    }
    return NOERROR;
}

ktfsdev::~ktfsdev()
{
    this->Release();
}

void ktfsdev::Dispose()
{
    delete this;
}

DzMutex g_IOBriageMutex;
DzEvent g_IOBriageEvent;

static void CDECL IOBriageISR(irq_t irq, void * pvDevice,
                InterruptContext * pContext)
{
    g_IOBriageEvent.NotifyByIsr();
}

physaddr_t IOAddress;

static Boolean IOBriageInit()
{
    DzRegisterIsr(15, IPL0, (isr_t)IOBriageISR, NULL);
    IOAddress = DzAllocPages(1, 0);
    if (IOAddress == INVALID_PAGE_ADDRESS) {
        kprintf("IOBriageInit, DzAllocPages Fail \n");
        return FALSE;
    }
    memset(__VA(IOAddress), 0, 2048);
    return TRUE;
}

EXTERN IDeviceDriver* CDECL CreateKtfs(uint_t uDeviceNo, void *pvParameter)
{
    ktfsdev *pKtfsDriver = new ktfsdev();
    if ((NULL == pKtfsDriver) || !IOBriageInit()) {
        return NULL;
    }
    pKtfsDriver->AddRef();
    return pKtfsDriver;
}
